package com.rabbit.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rabbit.constant.ResultCodeEnum;
import com.rabbit.db.entity.Role;
import com.rabbit.db.entity.RoleMenuMapping;
import com.rabbit.db.entity.UserRoleMapping;
import com.rabbit.exception.BusinessException;
import com.rabbit.mapper.RoleMapper;
import com.rabbit.mapper.RoleMenuMappingMapper;
import com.rabbit.mapper.UserRoleMappingMapper;
import com.rabbit.service.RoleService;
import com.rabbit.vo.req.RoleReq;
import com.rabbit.vo.res.RoleRes;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <h1>角色管理业务实现</h1>
 *
 * @author zjw
 * @date 2022/1/18 9:21
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private UserRoleMappingMapper userRoleMappingMapper;

    @Resource
    private RoleMenuMappingMapper roleMenuMappingMapper;

    @Override
    public PageInfo<RoleRes> queryRoleList(RoleReq roleReq) {
        Role role = Role.builder().build();
        BeanUtils.copyProperties(roleReq, role);
        return PageHelper.startPage(roleReq.getPage(), roleReq.getLimit())
                .doSelectPageInfo(() -> roleMapper.queryRoleList(role));
    }

    @Override
    public void checkIsAdmin(RoleReq roleReq) throws BusinessException {
        if (Objects.equals(roleReq.getRoleId(), 1L)) {
            throw new BusinessException(ResultCodeEnum.ROLE_ADMIN_UPDATE_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(RoleReq roleReq) {
        // 删除角色，角色菜单关联
        roleMapper.deleteByPrimaryKey(roleReq.getRoleId());
        RoleMenuMapping roleMenuMapping = RoleMenuMapping.builder().build();
        roleMenuMappingMapper.delete(roleMenuMapping);
    }

    @Override
    public void checkRoleUsed(RoleReq roleReq) throws BusinessException {
        UserRoleMapping userRoleMapping = UserRoleMapping.builder().roleId(roleReq.getRoleId()).build();
        if (userRoleMappingMapper.selectCount(userRoleMapping) > 0) {
            throw new BusinessException(ResultCodeEnum.ROLE_USED_ERROR);
        }
    }

    @Override
    public void updateRoleEnabled(RoleReq roleReq) {
        Role user = Role.builder().roleId(roleReq.getRoleId()).isEnabled(roleReq.getIsEnabled()).updateBy(roleReq.getOperatorUserName()).build();
        roleMapper.updateByPrimaryKeySelective(user);
    }

    @Override
    public RoleRes queryRoleById(Long roleId) {
        Role role = roleMapper.selectByPrimaryKey(roleId);
        RoleRes roleRes = RoleRes.builder().build();
        BeanUtils.copyProperties(role, roleRes);
        RoleMenuMapping roleMenuMapping = RoleMenuMapping.builder().roleId(roleId).build();
        List<RoleMenuMapping> mappings = roleMenuMappingMapper.select(roleMenuMapping);
        roleRes.setMenuIds(mappings.stream().map(RoleMenuMapping::getMenuId).collect(Collectors.toList()));
        return roleRes;
    }

    @Override
    public void checkUnique(RoleReq roleReq, int operType) throws BusinessException {
        // 1. 角色名称唯一
        Example roleNameExample = new Example(Role.class);
        Example.Criteria roleNameCriteria = roleNameExample.createCriteria();
        roleNameCriteria.andEqualTo("roleName", roleReq.getRoleName());
        if (operType > 1) {
            roleNameCriteria.andNotEqualTo("roleId", roleReq.getRoleId());
        }
        if (roleMapper.selectCountByExample(roleNameExample) > 0) {
            throw new BusinessException(ResultCodeEnum.ROLE_NAME_EXISTS_ERROR);
        }
        // 2. 角色Key唯一
        Example roleKeyExample = new Example(Role.class);
        Example.Criteria roleKeyCriteria = roleKeyExample.createCriteria();
        roleKeyCriteria.andEqualTo("roleKey", roleReq.getRoleKey());
        if (operType > 1) {
            roleKeyCriteria.andNotEqualTo("roleId", roleReq.getRoleId());
        }
        if (roleMapper.selectCountByExample(roleKeyExample) > 0) {
            throw new BusinessException(ResultCodeEnum.ROLE_KEY_EXISTS_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRole(RoleReq roleReq) {
        Role role = Role.builder().build();
        BeanUtils.copyProperties(roleReq, role);
        role.setIsEnabled(true);
        role.setCreateBy(roleReq.getOperatorUserName());
        roleMapper.insertSelective(role);
        insertRoleMenu(role.getRoleId(), roleReq.getMenuIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(RoleReq roleReq) {
        Role role = Role.builder().build();
        BeanUtils.copyProperties(roleReq, role);
        role.setUpdateBy(roleReq.getOperatorUserName());
        roleMapper.updateByPrimaryKeySelective(role);
        // 删除并添加角色菜单关联
        RoleMenuMapping roleMenuMapping = RoleMenuMapping.builder().roleId(roleReq.getRoleId()).build();
        roleMenuMappingMapper.delete(roleMenuMapping);
        insertRoleMenu(roleReq.getRoleId(), roleReq.getMenuIds());
    }

    /**
     * 添加角色菜单关联
     *
     * @param roleId  角色编号
     * @param menuIds 菜单编号
     */
    private void insertRoleMenu(Long roleId, List<Long> menuIds) {
        List<RoleMenuMapping> roleMenuMappings = new ArrayList<>();
        menuIds.forEach(e -> {
            RoleMenuMapping roleMenuMapping = RoleMenuMapping.builder().roleId(roleId).menuId(e).build();
            roleMenuMappings.add(roleMenuMapping);
        });
        roleMenuMappingMapper.insertList(roleMenuMappings);
    }
}
